<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Object.setPrototypeOf()与相关的方法</title>
</head>
<body>
  <script>
    // JavaScript语言的对象继承是通过原型链实现的，es6提供了更多原型对象的操作方法。
    /**
     *__proto__属性,用来读取或设置当前对象的原型对象(prototype)。目前，所有浏览器都部署了这个属性。
    */
    // es5 写法
    var obj = {
      method: function () {}
    };
    obj.__proto__ = someOtherObj;
    // es6的写法
    var obj = Object.create(someOtherObj);
    obj.method = function () {};
    /**
     * 该属性没有写入es6的正文，而是写入了附录，原因是__proto__前后的双下划线，说明它本质上是一个内部属性
     * 而不是一个正式的对外API, 只是由于浏览器广泛支持，才被加入了es6。标准明确规定，只有浏览器必须部署这个属性，
     * 其他环境不一定需要部署，而且新的代码最好认为这个属性是不存在的，因此，无论从语义的角度，还是从兼容性的角度，
     * 都不要使用这个属性，而是使用下面的
     * --Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.creat()(生成操作)代替
    */
   // 实现上， __proto__调用的是Object.prototype.__proto__,具体实现如下。
   Object.defineProperty(Object.prototype, '__proto__', {
     get() {
       var _thisObj = Object(this);
       return Object.getPrototypeOf(_thisObj);
     },
     set(proto) {
      if (this === undefined || this === null) {
        throw new TypeError();
      }
      if(!isObject(this)) {
        return undefined;
      }
      if (!isObject(proto)) {
        return undefined
      }
      var status = Reflect.setPrototypeOf(this, proto);
      if (!status) {
        throw new TypeError()
      }
     }
   });
   function isObject(value) {
     return Object(value) === value
   }
   // 如果一个对象本身部署了__proto__属性，该属性的值就是对象的元原型。
   Object.getPrototypeOf({__proto__: null}); // null
  </script>
  <script>
    // Object.setPrototypeOf() 方法作用与__proto__相同，用来设置一个对象的原型对象(prototype)
    // 返回参数对象本身，它是ES6正式推荐的设置原型对象的方法。
    // 格式
    // Object.setPrototypeOf(obj, prototype);
    // 用法
    var  o = Object.setPrototypeOf({}, null);
    //该方法等同于下面的函数
    function setPrototypeOf(obj, proto) {
      obj.__proto__ = proto;
      return obj
    }
    // 下面是一个例子
    var proto = {};
    var obj = {x: 10};
    Object,setPrototypeOf(obj, proto);
    proto.y = 20;
    proto.z = 40;
    console.log(obj) //
    /**
     * 上面代码将proto对象设置为obj对象的原型，所有从obj对象可以读取proto对象的属性，
     * 如果第一个参数不是对象，会自动转成对象。但是由于返回的还是第一个参数，所以
     * 这个操作不会产生任何效果。
    */
   Object.setPrototypeOf(1, {}) === 1; // true
   Object.setPrototypeOf('foo', {}) === 'foo'; // true
   Object.setPrototypeOf(true, {}) === true; // true
  //  由于undefined和null无法转为对象，所以如果第一个参数是undefined或null，就会报错。
  </script>
  <script>
    // getPrototypeOf()该方法用于读取一个对象的原型
    Object.getPrototypeOf({});
    // 下面是一个例子
    function Rectangle() {
      // ....
    }
    var rec = new Rectangle();
    Object.getPrototypeOf(rec) === Rectangle.prototype; // true
    Object.setPrototypeOf(rec, Object.prototype);
    Object.getPrototypeOf(rec) === Rectangle.prototype;
    // false
    // 同样，如果参数不是对象会被自动转为对象，undefined和null会报错。
  </script>
</body>
</html>